/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ca.ubc.icapture.genapha.actions;

import ca.ubc.icapture.genapha.forms.GeneSnpForm;
import icapture.SQLMgr;
import icapture.genapha.GenaphaTools;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jxl.read.biff.BiffException;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.Action;
import jxl.*;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMessage;
import org.biomoby.services.ncbi.NCBIJobManager;
import org.biomoby.services.ncbi.jobs.ChrRangeByGeneInfoFromXML;
import org.biomoby.services.ncbi.jobs.GeneInformationByEGeneID_GeneName;
import org.biomoby.services.ncbi.jobs.SnpBySnpInformationFromXML;
import org.biomoby.services.ncbi.jobs.SnpInformationByChrRangeFromXML;

/**
 *
 * @author ATan1
 */
public class GeneSnpAction extends Action {

    private HashMap<String, ArrayList<ArrayList>> geneSnpList = new HashMap();
    private String database;
    private String schema;
    private int offset = 0;

    @Override
    public ActionForward execute(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response) {
        ActionErrors errors = new ActionErrors();
        ActionForward forward = new ActionForward();
        //if not cleared, results from last query gets carried over.
        geneSnpList.clear();
        GeneSnpForm geneSnpForm = (GeneSnpForm) form;
        //sets the database name and corresponding schema with information from the form
        setDatabaseSchema(geneSnpForm);
        if (geneSnpForm.getSubmitType().isEmpty()) {
            return mapping.findForward("display");
        }
        //read in the file
        if (geneSnpForm.getUseTextarea().equals("text")) {
            ByteArrayInputStream bais = new ByteArrayInputStream(geneSnpForm.getTextInput().getBytes());
            ArrayList<String> inputContents = GenaphaTools.readFile(bais);
            readFile(inputContents, " ");
            forward = mapping.findForward("next");
        } else if (geneSnpForm.getFile() != null) {
            try {
                ArrayList<String> fileContents = GenaphaTools.readFile(geneSnpForm.getFile().getInputStream());
                offset = geneSnpForm.getStreamOffset() * 1000;
                //check for the content type, tab or comma or excel
                switch (determineFileType(fileContents.get(0))) {
                    case 0:
                        readFile(fileContents, ",");
                        break;
                    case 1:
                        readFile(fileContents, "\t");
                        break;
                    case 2:
                        readExcelFile(geneSnpForm.getFile().getInputStream());
                        break;
                }
                forward = mapping.findForward("next");
            } catch (Exception ex) {
                errors.add("geneSnp", new ActionMessage("geneSnp.error.readingFile"));
                forward = mapping.findForward("error");
            }
        }
            if (geneSnpList.size() > 0) {
                geneSnpForm.setGeneSnpHash(geneSnpList);
                request.getSession().setAttribute("geneSnpForm", geneSnpForm);
            }
            if (geneSnpForm.getExcel()) {
                forward = mapping.findForward("excel");
            }

        saveErrors(request, errors);
        return forward;
    }

    private void readExcelFile(InputStream in) throws BiffException, IOException, Exception {
        HashMap<String, String> geneIDtoName = new HashMap<String, String>();
        Workbook wb = Workbook.getWorkbook(in);
        Sheet sheet = wb.getSheet(0);
        Cell[] first = sheet.getColumn(0);
        Cell[] second = sheet.getColumn(1);
        for (int i = 0; i < first.length; ++i) {
            geneIDtoName.put(first[i].getContents(), second[i].getContents());
        }
        getGeneToSnp(geneIDtoName);
    }

    private int determineFileType(String testLine) {
        if (testLine.split(",").length == 2) {
            return 0;
        } else if (testLine.split("\t").length == 2) {
            return 1;
        } else {
            return 2;
        }
    }

    public void getGeneToSnp(HashMap geneList) throws Exception {
        //Take the input of geneID and geneName and get the Gene Information
        GeneInformationByEGeneID_GeneName geneInformationByEGeneID_GeneName = new GeneInformationByEGeneID_GeneName();
        geneInformationByEGeneID_GeneName.setGeneIdAndName(geneList);
        NCBIJobManager.runJob(geneInformationByEGeneID_GeneName); //allows jobs to be run every 3 seconds
        ArrayList<String[]> geneIDList = new ArrayList<String[]>();
        for (String[] snpInfo : geneInformationByEGeneID_GeneName.getGeneMap().values()) {
            if (snpInfo[0] != null && !snpInfo[0].equalsIgnoreCase("0")) {
                String[] tmp = {snpInfo[0], snpInfo[3]};
                //geneIDList contains the WebEnv call and the query number
                geneIDList.add(tmp);
            }
        }
        //Take the input of the geneID and get the chromosome range of the gene
        ChrRangeByGeneInfoFromXML chrRangeByGeneInfoFromXML = new ChrRangeByGeneInfoFromXML();
        chrRangeByGeneInfoFromXML.setChrInfo(geneIDList);
        NCBIJobManager.runJob(chrRangeByGeneInfoFromXML);
        int chrStart = 0;
        int chrEnd = 0;
        String chr = "0";
        HashMap<String,Object[]> rangeList = new HashMap<String,Object[]>();
        for (String id : chrRangeByGeneInfoFromXML.getGeneMap().keySet()) {
            String[] geneInfo = chrRangeByGeneInfoFromXML.getGeneMap().get(id);
            if (geneInfo[0] != null && !geneInfo[0].equalsIgnoreCase("0")) {
                //do the offset upstream+downstream
                chrStart = Integer.parseInt(geneInfo[3]) - offset;
                chrEnd = Integer.parseInt(geneInfo[4]) + offset;
                chr = geneInfo[0];
                Object[] tmp = {chr, chrStart, chrEnd};
                //range list contains the chromosome, the start and end positions of the gene
                rangeList.put(geneInfo[1]+"("+geneInfo[2]+")",tmp);
            }
        }
        //get some snp information from the range recorded above
        SnpInformationByChrRangeFromXML snpInformationByChrRangeFromXML = new SnpInformationByChrRangeFromXML();

        snpInformationByChrRangeFromXML.setGeneIdAndName(rangeList);

        NCBIJobManager.runJob(snpInformationByChrRangeFromXML);
        ArrayList<String[]> snpList1 = new ArrayList<String[]>();

        for (String id : snpInformationByChrRangeFromXML.getGeneMap().keySet()) {
            String[] geneInfo = snpInformationByChrRangeFromXML.getGeneMap().get(id);
            if (geneInfo[0] != null && !geneInfo[0].equalsIgnoreCase("0")) {
                //tmp contains the WebEnv, querynumber, and the amount of results found
                String[] tmp = {geneInfo[0], geneInfo[3], geneInfo[1]};
                snpList1.add(tmp);
            }
        }
        //get the RSNumber with a webenv call
        SnpBySnpInformationFromXML snpBySnpInformationFromXML = new SnpBySnpInformationFromXML();
        snpBySnpInformationFromXML.setChrInfo(snpList1);
        snpBySnpInformationFromXML.setChrStrEnd(rangeList);
        
        snpBySnpInformationFromXML.setDatabase(database);
        snpBySnpInformationFromXML.setSchema(schema);

        NCBIJobManager.runJob(snpBySnpInformationFromXML);
        geneSnpList = snpBySnpInformationFromXML.getSnpInfo();
    }

    private void readFile(ArrayList<String> fileContents, String delimiter) {
        try {
        HashMap<String, String> geneIDtoName = new HashMap<String, String>();
                                geneIDtoName.clear();
        for (String line : fileContents) {
                String[] lineSp = line.split(delimiter);
                geneIDtoName.put(lineSp[0], lineSp[1]);
            }
            getGeneToSnp(geneIDtoName);
            } catch (Exception ex) {
                Logger.getLogger(GeneSnpAction.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    private void setDatabaseSchema(GeneSnpForm geneSnpForm) {
        database = geneSnpForm.getDatabase();
        if (database == null || database.equals("")) {
            schema = "None";
        } else {
            try {
                //for now, database and schema info is obtained from context.xml
                //if db is defaultDatabase_qP9S, then using database and schema info from context.xml
                //need revisit this if necessary
                //in SQLMgr.java, method getAllRSNumbers: if it is current database, use the schema from context.xml
                //schema = SQLMgr.getSchemaFromName(database);
                schema="Default"; //the value will be ignored in SQLMgr.java, method getAllRSNumbers: if it is current database, use the schema info from context.xml
            } catch (Exception ex) {
                Logger.getLogger(GeneSnpAction.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
